﻿using Formatting = Newtonsoft.Json.Formatting;

namespace MicroCloud.Utils
{
    /// <summary>
    /// Json辅助扩展操作
    /// </summary>
    public static class JsonExtensions
    {
        #region "方法"
        #region "将对象转换为JSON字符串"
        /// <summary>
        /// 将对象转换为JSON字符串
        /// </summary> 
        /// <param name="obj">要转换的对象</param>
        /// <param name="camelCase">是否小写名称</param>
        /// <param name="indented">是否缩进</param>
        /// <param name="converters">序列化时使用的转换器集合</param>
        /// <returns>JSON字符串</returns>
        public static string ToJsonString(this object obj, bool camelCase = false, bool indented = false, params JsonConverter[] converters)
        {
            if (obj == null)
            {
                return "";
            }
            JsonSerializerSettings settings = new()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            };
            if (camelCase)
            {
                settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            }
            if (indented)
            {
                settings.Formatting = Formatting.Indented;
            }
            if (converters?.Length > 0)
            {
                settings.Converters = converters;
            }
            return JsonConvert.SerializeObject(obj, settings);
        }
        #endregion
        #region "将泛型对象转换为JSON字符串"
        /// <summary>
        /// 将泛型对象转换为JSON字符串
        /// </summary> 
        /// <param name="obj">要转换的泛型对象</param>
        /// <param name="camelCase">是否小写名称</param>
        /// <param name="indented">是否缩进</param>
        /// <param name="converters">序列化时使用的转换器集合</param>
        /// <returns>JSON字符串</returns>
        public static string ToJsonString<T>(this T obj, bool camelCase = false, bool indented = false, params JsonConverter[] converters)
            where T : class
        {
            if (obj == null)
            {
                return "";
            }
            JsonSerializerSettings settings = new()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            };
            if (camelCase)
            {
                settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            }
            if (indented)
            {
                settings.Formatting = Formatting.Indented;
            }
            if (converters?.Length > 0)
            {
                settings.Converters = converters;
            }
            return JsonConvert.SerializeObject(obj, settings);
        }
        #endregion
        #region "将JSON字符串转换为对象"
        /// <summary>
        /// 将JSON字符串转换为对象
        /// </summary> 
        /// <param name="jsonString">要转换的JSON字符串</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns></returns>
        public static object ToObject(this string jsonString, object defaultValue = default)
        {
            if (jsonString.IsMissing())
            {
                return defaultValue;
            }
            return JsonConvert.DeserializeObject(jsonString);
        }
        #endregion
        #region "将JSON字符串转换为指定类型的对象"
        /// <summary>
        /// 将JSON字符串转换为指定类型的对象
        /// </summary> 
        /// <param name="jsonString">要转换的JSON字符串</param>
        /// <param name="conversionType">目标对象类型</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns></returns>
        public static object ToObjectByType(this string jsonString, Type conversionType, object defaultValue = default)
        {
            if (jsonString.IsMissing())
            {
                return defaultValue;
            }
            return JsonConvert.DeserializeObject(jsonString, conversionType);
        }
        #endregion
        #region "将JSON字符串转换为泛型对象"
        /// <summary>
        /// 将JSON字符串转换为泛型对象
        /// </summary> 
        /// <param name="jsonString">要转换的JSON字符串</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns></returns>
        public static T ToModel<T>(this string jsonString, T defaultValue = default)
            where T : class
        {
            if (jsonString.IsMissing())
            {
                return defaultValue;
            }
            return JsonConvert.DeserializeObject<T>(jsonString);
        }
        #endregion

        #region "变更类型"
        /// <summary>
        /// 变更类型
        /// </summary>
        /// <typeparam name="T">源对象类型</typeparam>
        /// <param name="obj">源对象</param>
        /// <param name="conversionType">目标对象类型</param>
        /// <returns></returns>
        public static object ChangeType<T>(this T obj, Type conversionType)
        {
            JsonSerializerSettings settings = new()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            };
            var json = JsonConvert.SerializeObject(obj, settings);
            return JsonConvert.DeserializeObject(json, conversionType);
        }
        #endregion
        #region "变更类型"
        /// <summary>
        /// 变更类型
        /// </summary>
        /// <typeparam name="TSource">源对象类型</typeparam>
        /// <typeparam name="TDestination">目标对象类型</typeparam>
        /// <param name="obj">源对象</param>
        /// <returns></returns>
        public static TDestination ChangeType<TSource, TDestination>(this TSource obj)
        {
            JsonSerializerSettings settings = new()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            };
            var json = JsonConvert.SerializeObject(obj, settings);
            return JsonConvert.DeserializeObject<TDestination>(json);
        }
        #endregion

        #region "复制对象"
        /// <summary>
        /// 复制对象
        /// </summary> 
        /// <param name="obj">要复制的泛型对象</param>
        /// <returns></returns>
        public static T Copy<T>(this T obj)
            where T : class
        {
            JsonSerializerSettings settings = new()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            };
            var json = JsonConvert.SerializeObject(obj, settings);
            return JsonConvert.DeserializeObject<T>(json);
        }
        #endregion

        #endregion

    }

}
